/**
 * Copyright (C) 2025 pony working team
 * SPDX-License-Identifier: MulanPSL-2.0
 */

/* includes (local) ----------------------------------------------------------*/
#include <vfs_fatfs.h>
#include <vfs.h>
/* includes (standard library, system) ---------------------------------------*/
#include <string.h>
#include <stdio.h>
/* includes (other library) --------------------------------------------------*/
/* includes (project) --------------------------------------------------------*/
#include <x_module.h>
#include <hal_mtd.h>

/* defines -------------------------------------------------------------------*/

#define RAM_SECTOR_SIZE 512

/* typedefs ------------------------------------------------------------------*/
/* macro ---------------------------------------------------------------------*/
/* variables (extern) --------------------------------------------------------*/
/* variables (local) ---------------------------------------------------------*/

static volatile DSTATUS state = STA_NOINIT;
static hal_mtd_t *mtd = NULL;

/* variables (global) --------------------------------------------------------*/
/* inlines -------------------------------------------------------------------*/
/* functions -----------------------------------------------------------------*/

static DSTATUS mock_fatfs_status(disk_dev_t *dev)
{
    return state;
}

static DSTATUS mock_fatfs_initialize(disk_dev_t *dev)
{
    state = STA_NOINIT;

    if (mtd != NULL) {
        // init
        state &= ~STA_NOINIT;
    }
    return state;
}

static DRESULT mock_fatfs_read(disk_dev_t *dev, BYTE *buf, DWORD sector, UINT count)
{
    size_t len = (RAM_SECTOR_SIZE * count);
    size_t pos = 0;

    pos = sector * RAM_SECTOR_SIZE;
    hal_mtd_read(mtd, pos, len, buf);

    return RES_OK;
}

static DRESULT mock_fatfs_write(disk_dev_t *dev, const BYTE *buf, DWORD sector, UINT count)
{
    size_t len = (RAM_SECTOR_SIZE * count);
    size_t pos = 0;

    pos = sector * RAM_SECTOR_SIZE;
    hal_mtd_write(mtd, pos, len, buf);

    return RES_OK;
}

static DRESULT mock_fatfs_ioctl(disk_dev_t *dev, BYTE cmd, void *buf)
{
    DRESULT res = RES_OK;

    switch (cmd) {
    case CTRL_SYNC:
        break;
    case GET_SECTOR_COUNT:
        *(DWORD *)buf = mtd->total_size / RAM_SECTOR_SIZE;
        break;
    case GET_SECTOR_SIZE:
        *(WORD *)buf = RAM_SECTOR_SIZE;
        break;
    case GET_BLOCK_SIZE:
        *(DWORD *)buf = RAM_SECTOR_SIZE;
        break;
    default:
        res = RES_PARERR;
        break;
    }
    return res;
}

static struct disk_ops sram_ops = {
    .initialize = mock_fatfs_initialize,
    .status = mock_fatfs_status,
    .read = mock_fatfs_read,
    .write = mock_fatfs_write,
    .ioctl = mock_fatfs_ioctl,
};

int mock_fatfs_init(void)
{
    int8_t drive = -1;

    mtd = hal_mtd_open("ram");
    if (mtd == NULL) {
        return -1;
    }
    (void)fatfs_init();
    fatfs_mount("/fatfs/", &sram_ops, 0, (uint8_t *)&drive);

    return drive;
}

int mock_fatfs_exit(int drive)
{
    if (drive < 0) {
        return -1;
    }
    if (fatfs_unmount("/fatfs/", drive) != 0) {
        return -1;
    }
    fatfs_exit();
    mtd = NULL;
    return 0;
}

DWORD get_fattime(void)
{
    return 0;
}
